﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ITProject.Repository.Abstract;
using ITProject.WebUI.Models.Project;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using ITProject.Domain;
using ITProject.Domain.Entities;
using System.Diagnostics;

namespace ITProject.WebUI.Controllers
{
    /// <summary>
    /// Kontroler do zarządzania projektami.
    /// </summary>
    public partial class ProjectController : Controller
    {
        private IProjectRepository projectRepository;
        private IUserRepository userRepository;
        
        /// <summary>
        /// Konstruktor kontrolera projektów.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectRepo">Repozytorium projektów zbindowane przez biblioteke Ninject.</param>
        public ProjectController(IProjectRepository projectRepo, IUserRepository userRepo)
        {
            projectRepository = projectRepo;
            userRepository = userRepo;
        }
   
        /// <summary>
        /// Akcja do tworzenia projektu.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <returns>Zwraca widok w którym jest formularz z możlwością tworzenia projektu</returns>
        [Authorize]
        public virtual ViewResult Create()
        {
            return View(new ProjectCreateViewModel());
        }

        /// <summary>
        /// Akcja, która wykonuje się po utworzeniu projektu.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <returns>Zwraca widok główny nowo założonego projektu</returns>
        [Authorize]
        [HttpPost]
        public virtual ActionResult Create(ProjectCreateViewModel projectViewModel)
        {
            if (!ModelState.IsValid)
                return View("Create", projectViewModel);
            if (projectRepository.GetProjectByName(projectViewModel.Name) != null)
            {
                ModelState.AddModelError("Name", "Istnieje już projekt o takiej nazwie");
                return View("Create", projectViewModel);
            }
            if (projectViewModel.Logo != null)
            {
                if (projectViewModel.Logo.ContentLength > 0)
                {
                    string fileName = Path.GetFileName(projectViewModel.Logo.FileName);
                    int indexOfDot = fileName.LastIndexOf('.');
                    fileName=fileName.Insert(indexOfDot, DateTime.Now.ToString()).Replace(':', '.').Replace(" ", "");
                    var path = Path.Combine(HttpContext.Server.MapPath("/UserFiles/ProjectLogos"), fileName);
                    if (projectViewModel.Logo.ContentType != "image/jpeg" && projectViewModel.Logo.ContentType != "image/png")
                        ModelState.AddModelError("Logo", "Plik musi być obrazkiem");
                    else
                    {
                        using (Image image = Image.FromStream(projectViewModel.Logo.InputStream, true, true))
                        {
                            if (image.Width < ProjectCreateViewModel.MaxLogoWidth && image.Height < ProjectCreateViewModel.MaxLogoHeight)
                            {
                                projectViewModel.Logo.SaveAs(path);
                            }
                            else
                                ModelState.AddModelError("Logo", "Obraz nie może być większy niż " + ProjectCreateViewModel.MaxLogoWidth +
                                    "x" + ProjectCreateViewModel.MaxLogoHeight);
                        }
                    }
                }
                else
                    projectViewModel.Logo = null;
                if (!ModelState.IsValid)
                    return View("Create", projectViewModel);
            }
            var project=ProjectCreateViewModel.Convert(projectViewModel);
            string userName = HttpContext.ApplicationInstance.User.Identity.Name;
            projectRepository.Add(project,userName);

            //dodawanie repo
            Process pr;
            ProcessStartInfo psi = new ProcessStartInfo(@"cmd.exe", @"/C D: & cd SVN & mkdir " + project.Name
                + @" & svnadmin create --fs-type fsfs " + project.Name
                );
            psi.CreateNoWindow = true;
            psi.RedirectStandardInput = true;
            psi.UseShellExecute = false;
            pr = Process.Start(psi);
            StreamWriter swPlot = pr.StandardInput;
            pr.WaitForExit();

            return RedirectToAction(MVC.Project.ActionNames.Project, new { projectName=project.Name });
        }

        /// <summary>
        /// Metoda do wyświetlania listy projektów. Możliwe do przeglądania dla niezalogowanych użytkowników. We viewModelu logo, nazwa i krótki opis. 
        /// Po podaniu parametru zwraca szczegóły konkretnego projektu. Połączony z trasowaniem /Projekty/
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu do wyświetlenia.</param>
        /// <returns>Widok z listą projektów lub akcja ze szczegółami projektu.</returns>
        public virtual ActionResult Projects(string projectName)
        {
            if (projectName == null) // pokaż wszystkie projekty
            {
                ProjectProjectsViewModel[] projects = (ProjectProjectsViewModel[])ProjectProjectsViewModel.Convert(projectRepository.GetProjects());
                return View(projects);
            }
            return RedirectToAction(MVC.Project.ActionNames.Project, new { projectName = projectName });
        }

        /// <summary>
        /// Metoda do wyświetlenia szczegółów konkretnego projektu. Dostępne tylko dla zalogowanych użytkowników.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu do wyświetlenia.</param>
        /// <returns>Widok ze szczegółami projektu.</returns>
        [Authorize]
        public virtual ActionResult Project(string projectName)
        {
            Project p=projectRepository.GetProjectByName(projectName);
            ProjectProjectViewModel projectViewModel = ProjectProjectViewModel.Convert(p,projectRepository.GetProjectComment(p.Id),userRepository.GetAllUsers());
            projectViewModel.MenuViewModel = new ProjectMenuViewModel();
            projectViewModel.MenuViewModel.ProjectName = projectViewModel.Name;
            projectViewModel.MenuViewModel.Role=projectRepository.GetProjectUserRole(projectViewModel.Name, HttpContext.User.Identity.Name);
            projectViewModel.newComment.projectName=projectName;
            return View(projectViewModel);
        }

        /// <summary>
        /// Metoda do wyświetlenia uczestników danego projektu.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu</param>
        /// <returns>Widok uczestników projektu</returns>
        [Authorize]
        public virtual ViewResult ProjectUsers(string projectName)
        {
            ITProject.Domain.Entities.User[] users;
            UserRole[] projectUserRoles;
            projectRepository.GetProjectUsers(out users, out projectUserRoles, projectName);
            ProjectUserViewModel[] projectUsers = ProjectUserViewModel.Convert(users, projectUserRoles);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(projectUsers);
        }

        /// <summary>
        /// Metoda służąca do wyświetlania wszystkich zespołów w projeckie wraz ze składami.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="projectName">Nazwa projektu.</param>
        /// <returns>Widok wyświetlania zespołów.</returns>
        [Authorize]
        public virtual ViewResult ProjectTeams(string projectName)
        {
            Team[] teams;
            string[] leadres;
            User[][] users;
            projectRepository.GetProjectTeams(projectName, out teams, out leadres, out users);
            IEnumerable<ProjectTeamViewModel> vmList = ProjectTeamViewModel.Convert(teams, leadres, users);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vmList);
        }

        [Authorize]
        public virtual ViewResult ProjectReleases(string projectName)
        {
            int projectId=projectRepository.GetProjectId(projectName);
            Release[] releases=projectRepository.GetProjectReleases(projectId);
            StatusChange[][] statusChanges=new StatusChange[releases.Length][];
            string[][] statusChangesUserNames = new String[releases.Length][];
            for (int i=0; i<releases.Length; i++)
            {
                projectRepository.GetReleaseStatusChanges(releases[i], out statusChanges[i], out statusChangesUserNames[i]);
            }
            ProjectReleaseViewModel[] vmTab = ProjectReleaseViewModel.Convert(releases, statusChanges,statusChangesUserNames);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vmTab);
        }

        [Authorize]
        public virtual ViewResult ProjectFeatures(string projectName)
        {
            int projectId = projectRepository.GetProjectId(projectName);
            Feature[] features = projectRepository.GetProjectFeatures(projectId);
            string[] receivers = new string[features.Length];
            for (int i = 0; i < receivers.Length; i++)
            {
                if (features[i].IsToTeam)
                    receivers[i] = projectRepository.GetFeatureTeamByFeatureId(features[i].Id).Name;
                else
                    receivers[i] = projectRepository.GetFeatureUserByFeatureId(features[i].Id).Login;
            }
            StatusChange[][] statusChanges = new StatusChange[features.Length][];
            string[][] statusChangesUserNames = new String[features.Length][];
            for (int i = 0; i < features.Length; i++)
                projectRepository.GetFeatureStatusChanges(features[i], out statusChanges[i], out statusChangesUserNames[i]);
            ProjectFeatureViewModel[] vmTab = ProjectFeatureViewModel.Convert(features, receivers, statusChanges, statusChangesUserNames);
            ViewData["ProjectName"] = projectName;
            ViewData["Role"] = projectRepository.GetProjectUserRole(projectName, HttpContext.User.Identity.Name);
            return View(vmTab);
        }

        #region Zaproszenia do projetu

        /// <summary>
        /// Metoda sprawdza czy idUsera podane w acceptRejectString zgadza się z identyfikatorem obecnie zalogowanego użytkownika.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="uId">Identyfikator z acceptRejectString.</param>
        /// <returns>Prawda jeżeli przekazany identyfikator zgadza się z identyfikatorem zalogowanego użytkownika.</returns>
        private bool CanAcceptOrReject(int uId)
        {
            return uId == userRepository.GetUserByLogin(HttpContext.User.Identity.Name).Id;
        }

        /// <summary>
        /// Metoda pozwala na zaakceptowanie uczestnictwa w projekcie.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="acceptString">Łańcuch zaproszenia.</param>
        /// <returns>Widok potwierdzający lub błąd.</returns>
        [Authorize]
        public virtual ViewResult AcceptInvitation(string acceptString)
        {
            int uIndex = acceptString.IndexOf("u");
            int pId = Int32.Parse(acceptString.Substring(1, uIndex - 1));
            int uId = Int32.Parse(acceptString.Substring(uIndex + 1));
            if (!CanAcceptOrReject(uId)) // czy użytkownik zalogowany potwierdza swoje zaproszenie
                return View(MVC.Shared.Views.Error); // TO DO: dobre wyświetlenie błędu
            if (!projectRepository.AcceptInvitation(pId, uId))
                return View(MVC.Shared.Views.Error); // TO DO: dobre wyświetlenie błędu że nie ma zaproszenia
            ITProject.Domain.Entities.Project project= projectRepository.GetProjectById(pId);
            return View(MVC.Project.Views.AcceptInvitation,project.Name as object);
        }

        /// <summary>
        /// Metoda pozwala na odrzucenie zaproszenia uczestnictwa w projekcie.
        /// Autor: Jakub Szatkowski
        /// </summary>
        /// <param name="rejectString">Łańcuch zaproszenia.</param>
        /// <returns>Widok potwierdzający lub błąd.</returns>
        [Authorize]
        public virtual ViewResult RejectInvitation(string rejectString)
        {
            int uIndex = rejectString.IndexOf("u");
            int pId = Int32.Parse(rejectString.Substring(1, uIndex - 1));
            int uId = Int32.Parse(rejectString.Substring(uIndex + 1));
            if (!CanAcceptOrReject(uId)) // czy użytkownik zalogowany odrzuca swoje zaproszenie
                return View(MVC.Shared.Views.Error); // TO DO: dobre wyświetlenie błędu
            if (!projectRepository.RejectInvitation(pId, uId))
                return View(MVC.Shared.Views.Error); // TO DO: dobre wyświetlenie błędu że nie ma zaproszenia
            ITProject.Domain.Entities.Project project = projectRepository.GetProjectById(pId);
            return View(MVC.Project.Views.RejectInvitation, project.Name as object);
        }

        #endregion

        [Authorize]
        public virtual ActionResult AddComment()
        {
            ProjectCommentViewModel pc = new ProjectCommentViewModel();
            return View(pc);

        }
        [HttpPost]
        [Authorize]
        public virtual ActionResult AddComment(ProjectCommentViewModel p)
        {
            Comment c = new Comment();
            c.Text = p.Text;
            c.Id_User = userRepository.GetUserByLogin(User.Identity.Name).Id;
            c.Id_Project = projectRepository.GetProjectId(p.projectName);
            c.datetime = DateTime.Now;
            projectRepository.AddComment(c);
            return RedirectToAction(MVC.Project.ActionNames.Project, new { projectName = p.projectName });
        
        }
    }
}